package com.ruoyi.service.impl;

import com.google.gson.Gson;
import com.ruoyi.config.WxPayConfig;
import com.ruoyi.domain.*;
import com.ruoyi.enums.OrderStatusEnum;
import com.ruoyi.enums.WxApiType;
import com.ruoyi.enums.WxNotifyType;
import com.ruoyi.mapper.*;
import com.ruoyi.service.WxPayService;
import com.ruoyi.utils.OrderUtils;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.Base64;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
@Service
public class WxPayServiceImpl implements WxPayService {


    @Resource
    private WxPayConfig wxPayConfig;

    @Resource
    private CloseableHttpClient wxPayClient;

    @Autowired
    private AdvOrdersMapper advOrdersMapper;

    @Autowired
    private AdvIncomedetailMapper advIncomedetailMapper;
    @Autowired
    private AdvMembersMapper advMembersMapper;
    @Autowired
    private AdvIncomeMapper advIncomeMapper;

    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private final ReentrantLock lock = new ReentrantLock();

    /**
     * 创建订单，调用JSAPI支付接口
     *
     * @param advOrdersdetail
     * @return code_url 和 订单号
     * @throws Exception
     */
    @Override
    public Map<String, Object> jsapiPay(AdvOrdersdetail advOrdersdetail) throws IOException, NoSuchAlgorithmException, SignatureException, InvalidKeyException {

        System.out.println("调用统一下单API");

        String prepayId = "";  // prepayId 是微信的支付id

        AdvOrders advOrders = advOrdersMapper.getNoPayOrderByAdvOrdersId(advOrdersdetail.getAdvOrdersId());
        prepayId = advOrders.getPrepayId();
        // 这里会给每一个订单赋予一个新的订单号
        if (advOrders != null && !StringUtils.isEmpty(prepayId)) {
            if (advOrders.getOrdersno().substring(0,1).equals("D")){
                advOrders.setOrdersno(OrderUtils.genOrdersNo("D"));
            }else {
                advOrders.setOrdersno(OrderUtils.genOrdersNo("C"));
            }
            advOrdersMapper.updateOrderNoByNewOder(advOrders.getOrdersno(),advOrders.getAdvOrdersId());
        }

        //调用统一下单API
        String concat = wxPayConfig.getNotifyDomain().concat(WxNotifyType.JSAPI_NOTIFY.getType()); // 充配置中获取到通知类型
        System.out.println("支付通知--->"+concat);
        HttpPost httpPost = new HttpPost(wxPayConfig.getDomain().concat(WxApiType.JSAPI_PAY.getType()));
        //请求body参数
        Gson gson = new Gson();
        Map paramsMap = new HashMap();
        paramsMap.put("appid", wxPayConfig.getAppid());//"wx8f07d919706f3776"
        paramsMap.put("mchid", wxPayConfig.getMchId());
        paramsMap.put("description", "产品描述");
        paramsMap.put("out_trade_no", advOrders.getOrdersno());
        paramsMap.put("notify_url", wxPayConfig.getNotifyDomain().concat(WxNotifyType.JSAPI_NOTIFY.getType()));

        Map amountMap = new HashMap();
        Double ordersamount = advOrdersdetail.getOrdersamount();
        int amount = (int) Math.round(ordersamount * 100);  // 将浮点数金额乘以100后四舍五入到整数
        amountMap.put("total", amount);
        amountMap.put("currency", "CNY");
        paramsMap.put("amount", amountMap);

        Map openMap = new HashMap();
        openMap.put("openid", advOrdersdetail.getWeOpenid());
        paramsMap.put("payer", openMap);

        Map settle_info = new HashMap<>();
        settle_info.put("profit_sharing", true);
        paramsMap.put("settle_info", settle_info);


        String jsonParams = gson.toJson(paramsMap);
        System.out.println("请求参数 ===> {}" + jsonParams);
        StringEntity entity = new StringEntity(jsonParams, "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");

        //完成签名并执行请求  这个请求是用于在微信那边下单用的
        CloseableHttpResponse response = wxPayClient.execute(httpPost);
        try {
            String bodyAsString = EntityUtils.toString(response.getEntity());//响应体
            int statusCode = response.getStatusLine().getStatusCode();//响应状态码
            if (statusCode == 200) { //处理成功
                System.out.println("JSAPI成功, 返回结果 = " + bodyAsString);
            } else if (statusCode == 204) { //处理成功，无返回Body
                System.out.println("成功");
            } else {
                log.error("jsapiPay下单失败{}","JSAPI下单失败,响应码 = " + statusCode + ",返回结果 = " + bodyAsString);
                System.out.println("JSAPI下单失败,响应码 = " + statusCode + ",返回结果 = " + bodyAsString);
                throw new IOException("request failed");
            }

            //响应结果
            Map<String, String> resultMap = gson.fromJson(bodyAsString, HashMap.class);
            //二维码
            prepayId = resultMap.get("prepay_id");

            //保存二维码
            Long ordersId = advOrdersdetail.getAdvOrdersId();
            advOrdersMapper.savePrepayId(ordersId, prepayId);
            System.out.println("response----->" + response);
            // 获取所有的响应头

            Header[] headers = response.getAllHeaders();
            String wechatpaySignature = null; // 签名
            String wechatpayTimeStamp = null; // 时间
            String wechatpayNonce = null;  // 标志
            // 遍历响应头，找到 Wechatpay-Signature 微信支付签名
            for (Header header : headers) {
                if (header.getName().equals("Wechatpay-Signature")) {
                    wechatpaySignature = header.getValue();
                    System.out.println("Wechatpay-Signature: " + wechatpaySignature);
                    // 在这里可以对 Wechatpay-Signature 进行进一步处理
                } else if (header.getName().equals("Wechatpay-Timestamp")) {
                    wechatpayTimeStamp = header.getValue();
                    System.out.println("Wechatpay-Timestamp: " + wechatpayTimeStamp);
                } else if (header.getName().equals("Wechatpay-Nonce")) {
                    wechatpayNonce = header.getValue();
                    System.out.println("Wechatpay-Nonce: " + wechatpayNonce);
                }
            }

            //返回二维码
            Map<String, Object> map = new HashMap<>();
            map.put("prepay_id", prepayId);
            map.put("orderNo", ordersId);
            if (!wechatpaySignature.isEmpty()) {
                map.put("signature", getToken( wxPayConfig.getAppid(),"prepay_id="+prepayId,wechatpayTimeStamp,wechatpayNonce));
                map.put("timeStamp", wechatpayTimeStamp);
                map.put("nonce", wechatpayNonce);
                map.put("openid", wechatpayNonce);
            }
            return map;
        } finally {
            response.close();
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void processOrder(Map<String, Object> bodyMap) throws GeneralSecurityException {
        System.out.println("处理订单");

        //解密报文
        String plainText = decryptFromResource(bodyMap);

        System.out.println("myDATA_--------------------->" + plainText);
        //将明文转换成map
        Gson gson = new Gson();
        HashMap plainTextMap = gson.fromJson(plainText, HashMap.class);
        String orderNo = (String) plainTextMap.get("out_trade_no");
        String transactionId = (String) plainTextMap.get("transaction_id");
        String successTime = (String) plainTextMap.get("success_time");
        String appid = (String) plainTextMap.get("appid");

        /*在对业务数据进行状态检查和处理之前，
        要采用数据锁进行并发控制，
        以避免函数重入造成的数据混乱*/
        //尝试获取锁：
        // 成功获取则立即返回true，获取失败则立即返回false。不必一直等待锁的释放
        if (lock.tryLock()) {
            try {
                //处理重复的通知
                //接口调用的幂等性：无论接口被调用多少次，产生的结果是一致的。
                String orderStatus = advOrdersMapper.getOrderStatus(orderNo);
                if (!OrderStatusEnum.NOTPAY.getType().equals(orderStatus)) {
                    return;
                }

                String successTimeFormat = convertToMySqlFormat(successTime);
                //更新订单状态
                advOrdersMapper.updateStatusByOrder(orderNo, OrderStatusEnum.SUCCESS.getType(),plainText,transactionId,successTimeFormat);

            } finally {
                //要主动释放锁
                lock.unlock();
            }
        }
    }

    /**
     * 根据订单号查询微信支付查单接口，核实订单状态
     * 如果订单已支付，则更新商户端订单状态
     * 如果订单未支付，则调用关单接口关闭订单，并更新商户端订单状态
     *
     * @param orderNo
     */
    @Override
    public void checkOrderStatus(String orderNo) throws IOException {

//        System.out.println("根据订单号核实订单状态 ====>" + orderNo);

        //调用微信支付查单接口
        String result = this.queryOrder(orderNo);
        Gson gson = new Gson();
        Map resultMap = gson.fromJson(result, HashMap.class);
        //获取微信支付端的订单状态
        Object trade_state = resultMap.get("trade_state");
        Object transaction_id = resultMap.get("transaction_id");
        String successTime = (String) resultMap.get("success_time");

        //判断订单状态
        if ("SUCCESS".equals(trade_state)) {

//            System.out.println("核实订单已支付 ===>" + orderNo);
            String successTimeFormat = convertToMySqlFormat(successTime);
            //如果确认订单已支付则更新本地订单状态
            advOrdersMapper.updateStatusByOrder(orderNo,  OrderStatusEnum.SUCCESS.getType(),result, (String) transaction_id,successTimeFormat);

            // TXX增加的结算赠送订单
            AdvOrders advOrders = new AdvOrders();
            advOrders.setOrdersno(orderNo);
            List<AdvOrders> orders = advOrdersMapper.selectAdvOrdersList(advOrders);
            // 修改订单状态的时候需要把赠送的订单也设置为已经付款
            AdvOrders unsettled = null;
            AdvOrders dUnsettled = null;
            // 首先根据上传的信息判断当前用户是否存在未结算订单
            List<AdvOrders> unsettleds = advOrdersMapper.findUnsettled(orders.get(0).getAdvMembersId());
            // 表示是设备产品
            for (AdvOrders order : unsettleds) {
                if (order.getOrdersno().startsWith("S")) {
                    unsettled = order;
                }
                if (order.getOrdersno().startsWith("D")) {
                    dUnsettled = order;
                }
            }
            if(unsettled != null && dUnsettled.getAdvOrdersId().equals(advOrders.getAdvOrdersId())) {
                // 如果有赠送订单就结算
                AdvOrders giveOrders = new AdvOrders();
                giveOrders.setAdvOrdersId(unsettled.getAdvOrdersId());
                giveOrders.setOrderStatus(2L);
                advOrdersMapper.updateAdvOrders(giveOrders);
            }
        }

//        //未支付的处理
//        if ("NOTPAY".equals(trade_state)) {
//
//            System.out.println("核实订单未支付 ===>" + orderNo);
//            //如果订单未支付，则调用关单接口
//            this.closeOrder(orderNo);
//            //更新本地订单状态
//            advOrdersMapper.updateStatusByOrder(orderNo, OrderStatusEnum.NOTPAY.getType(),result,(String) transaction_id);
//
//        }

    }

    //调用微信查单接口
    @Override
    public String queryOrder(String orderNo) throws IOException {
        System.out.println("查单接口调用====>" + orderNo);

        String url = String.format(WxApiType.ORDER_QUERY_BY_NO.getType(), orderNo);

        url = wxPayConfig.getDomain().concat(url).concat("?mchid=").concat(wxPayConfig.getMchId());

        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("Accept", "application/json");

        //完成签名并执行请求
        CloseableHttpResponse response = wxPayClient.execute(httpGet);

        try {
            String bodyAsString = EntityUtils.toString(response.getEntity());//响应体
            int statusCode = response.getStatusLine().getStatusCode();//响应状态码
            if (statusCode == 200) { //处理成功
//                System.out.println("成功, 返回结果 = " + bodyAsString);
            } else if (statusCode == 204) { //处理成功，无返回Body
//                System.out.println("成功");
            } else {
//                System.out.println("JSAPI下单失败,响应码 = " + statusCode + ",返回结果 = " + bodyAsString);
                throw new IOException("request failed："+ bodyAsString);
            }

            return bodyAsString;
        } finally {
            response.close();
        }
    }

    /**
     * 退款
     *
     * @param advOrdersdetail
     * @throws Exception
     */
    @Override
    public void refund(AdvOrdersdetail advOrdersdetail) throws Exception {
        System.out.println("创建退款单记录");

        //根据订单编号创建退款单
        System.out.println("advOrdersdetail--->"+advOrdersdetail);
        AdvOrders advOrders = advOrdersMapper.getPayOrderByAdvOrdersId(advOrdersdetail.getAdvOrdersId());
        System.out.println("advOrders--->"+advOrders);
        System.out.println("advOrders.getOrdersno().substring(0, 1)--->"+advOrders.getOrdersno().substring(0, 1));
        String refundNo = OrderUtils.getRefundNo(advOrders.getOrdersno().substring(0, 1));
        advOrders.setOutRefundNo(refundNo);

        System.out.println("调用退款API");

        //调用统一下单API
        String url = wxPayConfig.getDomain().concat(WxApiType.DOMESTIC_REFUNDS.getType());
        HttpPost httpPost = new HttpPost(url);

        // 请求body参数
        Gson gson = new Gson();
        Map paramsMap = new HashMap();
        paramsMap.put("out_trade_no", advOrders.getOrdersno());//订单编号
        paramsMap.put("out_refund_no", advOrders.getOutRefundNo());//退款单编号
        paramsMap.put("reason", advOrdersdetail.getRemark());//退款原因
        paramsMap.put("notify_url", wxPayConfig.getNotifyDomain().concat(WxNotifyType.REFUND_NOTIFY.getType()));//退款通知地址

        Map amountMap = new HashMap();
        Double ordersamount = advOrdersdetail.getOrdersamount();

        int amount = (int) Math.round(ordersamount * 100);  // 将浮点数金额乘以100后四舍五入到整数

        amountMap.put("refund", amount);//退款金额
        amountMap.put("total", amount);//原订单金额
        amountMap.put("currency", "CNY");//退款币种
        paramsMap.put("amount", amountMap);

        //将参数转换成json字符串
        String jsonParams = gson.toJson(paramsMap);
        System.out.println("请求参数 ===> {}" + jsonParams);

        StringEntity entity = new StringEntity(jsonParams, "utf-8");
        entity.setContentType("application/json");//设置请求报文格式
        httpPost.setEntity(entity);//将请求报文放入请求对象
        httpPost.setHeader("Accept", "application/json");//设置响应报文格式
        //完成签名并执行请求，并完成验签
        CloseableHttpResponse response = wxPayClient.execute(httpPost);
        try {
            //解析响应结果
            String bodyAsString = EntityUtils.toString(response.getEntity());
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                System.out.println("成功, 退款返回结果 = " + bodyAsString);
            } else if (statusCode == 204) {
                System.out.println("成功");
            } else {
                throw new RuntimeException("退款异常, 响应码 = " + statusCode + ", 退款返回结果 = " + bodyAsString);
            }
            //更新订单状态
            advOrdersMapper.updateStatusByOrderRefund(advOrdersdetail.getOrdersno(), OrderStatusEnum.REFUND_PROCESSING.getType(),bodyAsString,refundNo);

        } finally {
            response.close();
        }

    }


    /**
     * 处理退款单
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void processRefund(Map<String, Object> bodyMap) throws Exception {
        System.out.println("退款单");
        //解密报文
        String plainText = decryptFromResource(bodyMap);
        //将明文转换成map
        Gson gson = new Gson();
        HashMap plainTextMap = gson.fromJson(plainText, HashMap.class);
        String orderNo = (String) plainTextMap.get("out_trade_no");
        String refundId = (String) plainTextMap.get("refund_id");
        if (lock.tryLock()) {
            try {
                String orderStatus = advOrdersMapper.getOrderStatus(orderNo);
                if (!OrderStatusEnum.REFUND_PROCESSING.getType().equals(orderStatus)) {
                    return;
                }
                //更新订单状态
                advOrdersMapper.updateStatusByOrderRefundId(orderNo, OrderStatusEnum.REFUND_SUCCESS.getType(),plainText,refundId);
            } finally {
                //要主动释放锁
                lock.unlock();
            }
        }
    }

    /**
     * 拒绝退款
     * @param advOrdersdetail
     */
    @Override
    public void NotReFunds(AdvOrdersdetail advOrdersdetail) {
        advOrdersMapper.updateStatusByOrderNotRefund(advOrdersdetail.getRemark(),advOrdersdetail.getAdvOrdersId(),OrderStatusEnum.ORDER_OVER.getType());
    }

    /**
     * 执行添加分账人以及申请分账的流程
     * @param advIncome
     * @return
     */
    @Override
    public boolean exePayShare(AdvIncome advIncome,List<AdvIncomedetail> list) throws IOException {
        long memberId = Long.parseLong(advIncome.getAdvMembersId());
        //查询到本人会员信息
        AdvMembers advMembers = advMembersMapper.selectAdvMembersByAdvMembersId(memberId);
        //遍历下级和本级订单
        for (AdvIncomedetail advIncomedetail : list) {
            //对于本级订单
            if (advIncomedetail.getAdvMembersId().equals(advIncome.getAdvMembersId())){
                //父级id不为空
                if (advMembers.getParentAccount()!=null) {
                    //查询订单信息
                    AdvOrders advOrders = advOrdersMapper.selectAdvOrdersByAdvOrdersId(advIncomedetail.getAdvOrdersId());
                    //调用查询分账接口
                    boolean parentTag = this.checkOrderShareStatus(advIncomedetail.getOrdersno(), advMembers.getWeOpenid(), advOrders.getTransactionId());
                    //请求分账
                    System.out.println("分账金额--->"+Double.valueOf(advIncomedetail.getOrderAmount())+",税率--->"+advIncomedetail.getTaxRate());
                    requestShare(advOrders.getTransactionId(),advMembers.getWeOpenid(),advOrders.getOrdersno(),Double.valueOf(advIncomedetail.getOrderAmount()),advIncomedetail.getTaxRate(),parentTag);
                }
            }else {
                //对于下级订单
                AdvIncome lowIncome = advIncomeMapper.selectAdvIncomeByAdvIncomeId(advIncomedetail.getAdvIncomeId());
                //查询订单信息
                AdvOrders advOrders = advOrdersMapper.selectAdvOrdersByAdvOrdersId(advIncomedetail.getAdvOrdersId());
                boolean lowTag = false;
                if (lowIncome.getIsSendcash().equals("1")){
                    lowTag = true;
                }
                requestShare(advOrders.getTransactionId(),advMembers.getWeOpenid(),advOrders.getOrdersno(),Double.valueOf(advIncomedetail.getOrderAmount()),advIncomedetail.getTaxRate(),lowTag);
            }
            System.out.println("下级和本级--->"+advIncomedetail);
        }
        advIncome.setIsSendcash("1");
        advIncome.setSenccashDate(simpleDateFormat.format(new Date()));
        advIncomeMapper.updateAdvIncome(advIncome);
        return true;
    }

    @Override
    public void exeAddShare(AdvMembers advMembers) throws IOException {
        System.out.println(advMembers);
        advMembersMapper.updateAdvMembers(advMembers);
        addSharePerson(advMembers.getWeOpenid());
    }


    /**
     * 添加分账用户
     * @throws IOException
     */
    private void addSharePerson(String account) throws IOException {
        HttpPost httpPost = new HttpPost(wxPayConfig.getDomain().concat(WxApiType.ADD_SHARE_PERSON.getType()));
        Gson gson = new Gson();
        Map paramsMap = new HashMap();
        paramsMap.put("appid", wxPayConfig.getAppid());
        paramsMap.put("type", "PERSONAL_OPENID");
        paramsMap.put("account", account);
        paramsMap.put("relation_type", "USER");

        //将参数转换成json字符串
        String jsonParams = gson.toJson(paramsMap);
        System.out.println("分账参数" + jsonParams);

        StringEntity entity = new StringEntity(jsonParams, "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");

        //完成签名并执行请求
        CloseableHttpResponse response = wxPayClient.execute(httpPost);

        try {
            String bodyAsString = EntityUtils.toString(response.getEntity());//响应体
            int statusCode = response.getStatusLine().getStatusCode();//响应状态码
            if (statusCode == 200) { //处理成功
                System.out.println("添加分账成功 = " + bodyAsString);
            } else if (statusCode == 204) { //处理成功，无返回Body
                System.out.println("成功");
            } else {
                System.out.println("添加分账失败,响应码 = " + statusCode + ",返回结果 = " + bodyAsString);
                throw new IOException("request failed");
            }
        } finally {
            response.close();
        }
    }




    /**
     * 发起分账请求
     * @param transactionId
     * @param outOrderNo
     * @throws IOException
     */
    private void requestShare(String transactionId, String account,String outOrderNo,Double ordersamount,Long percent,boolean shareTag) throws IOException {
        HttpPost httpPost = new HttpPost(wxPayConfig.getDomain().concat(WxApiType.SEND_SHARE.getType()));
        Gson gson = new Gson();
        Map paramsMap = new HashMap();
        paramsMap.put("appid", wxPayConfig.getAppid());
        paramsMap.put("transaction_id", transactionId);
        paramsMap.put("out_order_no", outOrderNo);
        paramsMap.put("unfreeze_unsplit", shareTag);

        // 将 ordersamount 单位元转换为分，percent 是百分比，需要除以 100
        int amount = (int) (ordersamount * percent / 100 * 100);
        System.out.println("分账金额----->"+amount);
        Map<String, Object> receiver1 = new HashMap<>();
        receiver1.put("type", "PERSONAL_OPENID"); // 设置分账接收方类型
        receiver1.put("account", account); // 设置分账接收方帐号
        receiver1.put("amount", amount); // 设置分账金额，单位为分
        receiver1.put("description", "分帐"); // 设置分账描述

        // 将第一个接收方的Map对象添加到receivers列表中
        List<Map<String, Object>> receivers = new ArrayList<>();
        receivers.add(receiver1);
        paramsMap.put("receivers", receivers);
//        Map map = new HashMap();
//        map.put("type","PERSONAL_OPENID");
//        map.put("account","olfG466S1Vb0mIL7f8CRY7KM3kH8");
//        map.put("amount",2);
//        map.put("description","分给a");
//        paramsMap.put("receivers",map);

        //将参数转换成json字符串
        String jsonParams = gson.toJson(paramsMap);
        System.out.println("分账参数" + jsonParams);

        StringEntity entity = new StringEntity(jsonParams, "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");

        //完成签名并执行请求
        CloseableHttpResponse response = wxPayClient.execute(httpPost);
        try {
            String bodyAsString = EntityUtils.toString(response.getEntity());//响应体
            int statusCode = response.getStatusLine().getStatusCode();//响应状态码
            if (statusCode == 200) { //处理成功
                System.out.println("分账成功 " + bodyAsString);
            } else if (statusCode == 204) { //处理成功，无返回Body
                System.out.println("成功");
            } else {
                System.out.println("分账失败,响应码 = " + statusCode + ",返回结果 = " + bodyAsString);
                throw new IOException("request failed");
            }
        } finally {
            response.close();
        }
    }


    //解析分账查询接口返回报文
    @Override
    public boolean checkOrderShareStatus(String orderNo,String memberId,String transactionId) throws IOException {
        boolean response = false;
//        System.out.println("根据订单号核实订单状态 ====>" + orderNo);

        //调用微信支付查单接口
        String result = this.queryOrderByShare(orderNo,transactionId);
        Gson gson = new Gson();
        System.out.println("分账查询报文----->"+result);
        Map resultMap = gson.fromJson(result, HashMap.class);
        //获取微信支付端的订单状态
//        Object transactionId = resultMap.get("transaction_id");
//        Object outOrderNo = resultMap.get("out_order_no");
        String orderId = (String) resultMap.get("order_id");
        String state = (String) resultMap.get("state");
        // 获取 receivers 字段并解析
        List<Map<String, Object>> receivers = (List<Map<String, Object>>) resultMap.get("receivers");
        if (receivers!=null){
            // 处理 receivers 数据
            for (Map<String, Object> receiver : receivers) {
                String account = (String) receiver.get("account");
                String resultStatus = (String) receiver.get("result");
                String failReason = (String) receiver.get("fail_reason");
                String createTime = (String) receiver.get("create_time");
                String finishTime = (String) receiver.get("finish_time");
                String detailId = (String) receiver.get("detail_id");
                if (memberId!=null){
                    if (memberId.equals(account)&&resultStatus.equals("SUCCESS")) {
                        response =  true;
                    }
                }
                System.out.println("Account: " + account);
                System.out.println("Result: " + resultStatus);
                System.out.println("Fail Reason: " + failReason);
                System.out.println("Create Time: " + createTime);
                System.out.println("Finish Time: " + finishTime);
                System.out.println("Detail ID: " + detailId);
            }
        }
        return response;
    }

    //调用微信查询分账结果接口返回报文
    @Override
    public String queryOrderByShare(String orderNo,String transactionId) throws IOException {

//        System.out.println("查单接口调用====>" + orderNo);

        String url = String.format(WxApiType.SHARE_RESULT.getType(), orderNo);

        url = wxPayConfig.getDomain().concat(url).concat("?mchid=").concat(wxPayConfig.getMchId());

        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("Accept", "application/json");

        //完成签名并执行请求
        CloseableHttpResponse response = wxPayClient.execute(httpGet);

        try {
            String bodyAsString = EntityUtils.toString(response.getEntity());//响应体
            int statusCode = response.getStatusLine().getStatusCode();//响应状态码
            if (statusCode == 200) { //处理成功
//                System.out.println("成功, 返回结果 = " + bodyAsString);
            } else if (statusCode == 204) { //处理成功，无返回Body
//                System.out.println("成功");
            } else {
//                System.out.println("JSAPI下单失败,响应码 = " + statusCode + ",返回结果 = " + bodyAsString);
                throw new IOException("request failed："+ bodyAsString);
            }

            return bodyAsString;
        } finally {
            response.close();
        }
    }


    /**
     * 日期格式转换
     * @param isoDateTime
     * @return
     */
    public static String convertToMySqlFormat(String isoDateTime) {
        // 解析输入字符串为 ZonedDateTime 对象
        ZonedDateTime zonedDateTime = ZonedDateTime.parse(isoDateTime);

        // 将 ZonedDateTime 转换为 LocalDateTime
        LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();

        // 定义所需的日期时间格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 格式化 LocalDateTime 为所需的字符串格式
        return localDateTime.format(formatter);
    }


    /**
     * 关单接口的调用
     *
     * @param orderNo
     */
    private void closeOrder(String orderNo) throws IOException {

        System.out.println("关单接口的调用，订单号 ==>" + orderNo);

        //创建远程请求对象
        String url = String.format(WxApiType.CLOSE_ORDER_BY_NO.getType(), orderNo);
        url = wxPayConfig.getDomain().concat(url);
        HttpPost httpPost = new HttpPost(url);


        //组装JSON请求体
        Gson gson = new Gson();
        HashMap<String, String> paramsMap = new HashMap<>();
        paramsMap.put("mchid", wxPayConfig.getMchId());
        String jsonParams = gson.toJson(paramsMap);
        System.out.println("请求参数----》" + jsonParams);

        //将请求参数设置到请求对象中
        StringEntity entity = new StringEntity(jsonParams, "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");

        //完成签名并执行请求
        CloseableHttpResponse response = wxPayClient.execute(httpPost);


        try {

            int statusCode = response.getStatusLine().getStatusCode();//响应状态码
            if (statusCode == 200) { //处理成功
                System.out.println("成功");
            } else if (statusCode == 204) { //处理成功，无返回Body
                System.out.println("成功");
            } else {
                System.out.println("Native下单失败,响应码 = " + statusCode);
                throw new IOException("request failed");
            }
        } finally {
            response.close();
        }

    }

    //获取支付token
    public String getToken(String appid, String prepay_id, String timestamp, String nonceStr) throws IOException, SignatureException, NoSuchAlgorithmException, InvalidKeyException {

        long l = Long.parseLong(timestamp);

        //从下往上依次生成
        String message = buildMessage(appid, l, nonceStr, prepay_id);
        //签名
        String signature = sign(message.getBytes("utf-8"));
        return signature;
    }

    public String sign(byte[] message) throws NoSuchAlgorithmException, SignatureException, IOException, InvalidKeyException {
        //签名方式
        Signature sign = Signature.getInstance("SHA256withRSA");
        //私钥，通过MyPrivateKey来获取，这是个静态类可以接调用方法 ，需要的是_key.pem文件的绝对路径配上文件名
        sign.initSign(getPrivateKey(wxPayConfig.getPrivateKeyPath()));
        sign.update(message);

        return Base64.getEncoder().encodeToString(sign.sign());
    }


    public PrivateKey getPrivateKey(String filename) throws IOException {
        ClassLoader classLoader = getClass().getClassLoader();
        try (InputStream inputStream = classLoader.getResourceAsStream(filename);
             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
            if (inputStream == null) {
                throw new FileNotFoundException("File not found: " + filename);
            }

            StringBuilder contentBuilder = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                contentBuilder.append(line).append("\n");
            }

            String content = contentBuilder.toString();

            String privateKey = content
                    .replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s+", "");

            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getMimeDecoder().decode(privateKey)));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持RSA", e);
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException("无效的密钥格式");
        }
    }


//    public PrivateKey getPrivateKey(String filename) throws IOException {
//        Path path = Paths.get(filename);
//        if (Files.notExists(path)) {
//            throw new FileNotFoundException("File not found: " + filename);
//        }
//        String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8");
//        try {
//            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
//                    .replace("-----END PRIVATE KEY-----", "")
//                    .replaceAll("\\s+", "");
//
//            KeyFactory kf = KeyFactory.getInstance("RSA");
//            return kf.generatePrivate(
//                    new PKCS8EncodedKeySpec(Base64.getMimeDecoder().decode(privateKey)));
//        } catch (NoSuchAlgorithmException e) {
//            throw new RuntimeException("当前Java环境不支持RSA", e);
//        } catch (InvalidKeySpecException e) {
//            throw new RuntimeException("无效的密钥格式");
//        }
//    }

    /**
     * 按照前端签名文档规范进行排序，\n是换行
     *
     * @param appid
     * @param timestamp
     * @param nonceStr
     * @param prepay_id
     * @return
     */
    public String buildMessage(String appid, long timestamp, String nonceStr, String prepay_id) {

        return appid + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + prepay_id + "\n";
    }

    /**
     * 对称解密
     *
     * @param bodyMap
     * @return
     */
    private String decryptFromResource(Map<String, Object> bodyMap) throws GeneralSecurityException {

        System.out.println("密文解密");

        //通知数据
        Map<String, String> resourceMap = (Map) bodyMap.get("resource");
        //数据密文
        String ciphertext = resourceMap.get("ciphertext");
        //随机串
        String nonce = resourceMap.get("nonce");
        //附加数据
        String associatedData = resourceMap.get("associated_data");

        System.out.println("密文 ===> " + ciphertext);
        AesUtil aesUtil = new AesUtil(wxPayConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8));
        String plainText = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8),
                nonce.getBytes(StandardCharsets.UTF_8),
                ciphertext);

        System.out.println("明文 ===> " + plainText);

        return plainText;
    }

}
